package com.sunyard.utils;

import cn.hutool.core.convert.Convert;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.google.common.base.Preconditions;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.common.jaxb.JAXBUtils;
import org.dom4j.*;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.StringUtils;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.*;

/**
 * xml解析工具
 *
 * @author xiaoGang
 * @date 2019年4月13日09:31:11
 */
@Slf4j
public final class XmlParseUtil {

    /**
     * xml对象
     */
    private final static Map<String, Document> DOCUMENT_MAP = new HashMap<>();

    public static Map<String, Document> getDocumentMap() {
        return DOCUMENT_MAP;
    }

    /**
     * 加载某个文件夹下的所有xml
     *
     * @param filePath 文件路径，需要以斜杠结尾
     * @throws IOException
     * @throws DocumentException
     */
    public static void loadXmlList(String filePath) throws IOException, DocumentException {
        //创建SAXReader对象
        SAXReader reader = new SAXReader();
        Resource[] resources = new PathMatchingResourcePatternResolver().getResources(filePath + "*.xml");
        for (Resource resource : resources) {
            InputStream inputStream = resource.getInputStream();
            //通过read的方法读取一个文件转换成Document对象
            final Document document = reader.read(inputStream);
            log.info("加载XML：" + resource.getFilename());
            //存入缓存
            DOCUMENT_MAP.put(resource.getFilename(), document);
        }
    }

    /**
     * 流加载xml
     *
     * @author xiaog.li
     * @date 2019/5/15 11:00
     */
    @Deprecated
    static void loadDocument(InputStream inputStream, String fileName) throws DocumentException {
        log.info("加载XML：" + fileName);
        //创建SAXReader对象
        SAXReader reader = new SAXReader();
        //通过read的方法读取一个文件转换成Document对象
        final Document document = reader.read(inputStream);
        //存入缓存
        DOCUMENT_MAP.put(fileName, document);
    }

    /**
     * 加载某个包路径下的所有xml
     *
     * @param filePath
     * @return
     */
    @Deprecated
    public static void loadDocument(String filePath) throws DocumentException {
        URL path = com.sunyard.utils.XmlParseUtil.class.getResource(filePath);
        //创建文件对象
        File fileDirectory = new File(path.getFile());
        if (fileDirectory.isDirectory()) {
            //判断是否为文件夹
            File[] files = fileDirectory.listFiles();
            for (File file : files) {
                log.info("加载XML：" + file.getName());
                //创建SAXReader对象
                SAXReader reader = new SAXReader();
                //通过read的方法读取一个文件转换成Document对象
                Document document = reader.read(file);
                //存入缓存
                DOCUMENT_MAP.put(file.getName(), document);
            }
        }
    }

    /**
     * 报文交易 实体类与xml同节点
     *
     * @param object
     * @param fileName
     * @return
     * @throws Exception
     */
    public static boolean verify(Object object, String fileName) {
        log.info("校验XML：" + fileName);
        Document document = DOCUMENT_MAP.get(fileName);
        Preconditions.checkArgument(document != null, "交易类型错误" + fileName);
        Element root = document.getRootElement();
        return getNodes(object, root);
    }


    /**
     * 递归判断
     *
     * @author xiaog.li
     * @date 2019/7/10 18:11
     */
    private static boolean getNodes(Object object, Element root) {
        //转json数据
        List<Element> elementList = root.elements();
        //判断是否有子节点
        if (elementList.size() > 0) {
            String json = JSON.toJSONString(object);
            //获取json对象
            JSONObject jsonObject = JSONObject.parseObject(json);
            //有子节点
            for (Element element : elementList) {
                Object obj = jsonObject.get(element.getName());
                Attribute nullable = element.attribute("nullable");
                Attribute nameAttr = element.attribute("name");
                //判断是否为空
                if (nullable != null && "false".equals(nullable.getValue())) {
                    if (StringUtils.isEmpty(obj)) {
                        log.info("[" + element.getName() + ":" + nameAttr.getValue() + "]为空");
                        throw new NullPointerException("[" + element.getName() + ":" + nameAttr.getValue() + "]为空");
                    } else {
                        /*字段不为空，递归循环*/
                        if (!getNodes(obj, element)) {
                            return false;
                        }
                    }
                } else {
                    //属性不存在
                    if (StringUtils.isEmpty(obj)) {
                        //字段值为空 结束当前循环
                        continue;
                    } else {
                        //字段不为空，递归寻循环
                        if (!getNodes(obj, element)) {
                            return false;
                        }
                    }
                }

            }
        } else {
            Attribute nullable = root.attribute("nullable");
            Attribute maxlen = root.attribute("maxlen");
            Attribute nameAttr = root.attribute("name");
            if (nullable != null && "false".equals(nullable.getValue())) {
                if (StringUtils.isEmpty(object)) {
                    log.info("[" + root.getName() + ":" + nameAttr.getValue() + "]为空");
                    throw new NullPointerException("[" + root.getName() + ":" + nameAttr.getValue() + "]为空");
                } else {
                    //判断长度
                    if (maxlen != null) {
                        Integer nMaxLen = Convert.toInt(maxlen.getValue());
                        Integer nCurLen = Convert.toStr(object).length();
                        if (nCurLen > nMaxLen) {
                            log.info("[" + root.getName() + ":" + nameAttr.getValue() + "]长度不能超过" + nMaxLen + "字符");
                            throw new NullPointerException("[" + root.getName() + ":" + nameAttr.getValue() + "]长度不能超过" + nMaxLen + "字符");
                        }
                    }
                }
            } else {
                //可为空的情况
                //判断长度
                if (maxlen != null) {
                    Integer nMaxLen = Convert.toInt(maxlen.getValue());
                    Integer nCurLen = Convert.toStr(object).length();
                    if (nCurLen > nMaxLen) {
                        log.info("[" + root.getName() + ":" + nameAttr.getValue() + "]长度不能超过" + nMaxLen + "字符");
                        throw new NullPointerException("[" + root.getName() + ":" + nameAttr.getValue() + "]长度不能超过" + nMaxLen + "字符");
                    }
                }
            }
        }
        return true;
    }

    /**
     * xml 转实体类
     *
     * @param xmlValue
     * @param clazz
     * @param <T>
     * @return
     * @throws Exception
     */
    public static <T> T toBean(String xmlValue, Class<T> clazz) throws UnsupportedEncodingException, DocumentException, IllegalAccessException, InstantiationException, NoSuchFieldException {
        //创建SAXReader对象
        log.info("xml开始转换实体...");
        SAXReader reader = new SAXReader();
        //通过read的方法读取一个文件转换成Document对象
        Document document = reader.read(new ByteArrayInputStream(xmlValue.getBytes(StandardCharsets.UTF_8)));
        //获取根节点元素
        Element root = document.getRootElement();

        T object = clazz.newInstance();
        setFields(object, root);
        return object;
    }

    /**
     * 递归设置字段值
     *
     * @param object
     * @param root
     * @throws Exception
     */
    public static void setFields(Object object, Element root) throws NoSuchFieldException, IllegalAccessException {
        List<Element> elements = root.elements();
        //判断是否有子节点
        if (elements.size() > 0) {
            //有，循环递归
            for (Element element : elements) {
                setFields(object, element);
            }
        } else {
            setFieldValue(object, root.getName(), root.getTextTrim(), root);
        }
    }

    /**
     * 转xml
     *
     * @param
     * @param fileName
     * @return
     */
    public static String toXml(Object object, String fileName) throws UnsupportedEncodingException, DocumentException, NoSuchFieldException, IllegalAccessException {
        Document initDocument = DOCUMENT_MAP.get(fileName);

        if (initDocument == null) {
            throw new NullPointerException(fileName + " xml对象不存在");
        }
        String xmlValue = initDocument.asXML().trim();
        //创建SAXReader对象
        SAXReader reader = new SAXReader();
        //通过read的方法读取一个文件转换成Document对象
        Document document = reader.read(new ByteArrayInputStream(xmlValue.getBytes("UTF-8")));
        if (document == null) {
            throw new NullPointerException(fileName + " xml对象不存在");
        }
        Element root = document.getRootElement();
        if (!setNodes(object, root)) {
            //表示报文验证错误
            return null;
        }
        //删除备注信息
        Iterator<Node> iterator = document.nodeIterator();
        while (iterator.hasNext()) {
            Node node = iterator.next();
            if (node.getNodeType() == Node.COMMENT_NODE) {
                //删除备注
                document.remove(node);
            }
        }
        deleteXmlNotation(document.getRootElement());

        //String xml = document.asXML();
        //使用对称标签
        String xml = asXml(document);
//        log.info("多渠道XML报文：\n" + xml);
        // xml.replaceAll("\n\n","\n");
        return xml;
        //return xml.replaceAll("\n", "");
    }

    /**
     * 去掉注释
     *
     * @param ele
     */
    public static void deleteXmlNotation(Element ele) {
        Iterator<Node> nodes = ele.nodeIterator();
        List<Node> rmNodes = new ArrayList<Node>();
        //循环收集可以删除的节点
        while (nodes.hasNext()) {
            Node subNode = nodes.next();
            if (subNode.getNodeType() == Node.COMMENT_NODE) {
                //ele.remove(subNode);
                rmNodes.add(subNode);
                rmNodes.add(nodes.next());
            }
        }
        //删除收集到的节点
        for (Node node : rmNodes) {
            ele.remove(node);
        }
        //递归，处理下级节点
        Iterator<Element> eleIt = ele.elementIterator();
        while (eleIt.hasNext()) {
            deleteXmlNotation(eleIt.next());
        }
    }

    private static String asXml(Document document) {
        OutputFormat format = new OutputFormat();
        format.setEncoding(document.getXMLEncoding());
        format.setExpandEmptyElements(true);
        StringWriter out = new StringWriter();
        XMLWriter writer = new XMLWriter(out, format);
        try {
            writer.write(document);
            writer.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return out.toString();
    }

    /**
     * 递归遍历xml节点，并更改值
     * <p>
     * 实体类全部一级，xml有子节点
     *
     * @param object
     * @param root
     * @throws Exception
     */
    public static boolean setNodes(Object object, Element root) throws NoSuchFieldException, IllegalAccessException {
        //判断type是否为list
        String type = root.attributeValue("type");
        if ("list".equals(type) || "listT272001".equals(type) || "listT271020".equals(type)) {
            return setListNodes(object, root, type);
        } else {


            List<Element> elements = root.elements();

            //判断是否有子节点
            if (elements.size() > 0) {
                //有，循环递归
                //去掉属性
                removeAttribute(root);
                for (Element element : elements) {
                    if (!setNodes(object, element)) {
                        return false;
                    }
                }
            } else {
                //没有，更改字节点的值
                if (StringUtils.isEmpty(root.getTextTrim())) {
                    //当节点没有默认值时，更改值
                    log.info("开始获取元素节点信息" + root.getName());
                    Attribute attribute = root.attribute("nullable");
                    Attribute attributeParent = root.attribute("parent");
                    Attribute nameAttr = root.attribute("name");
                    Attribute maxlenAttr = root.attribute("maxlen");
                    Attribute minlenAttr = root.attribute("minlen");
                    //判断是否为转换节点，转换节点的需要字段需要'_'同'-'
                    Attribute conversionAttr = root.attribute("conversion");
                    if (attribute != null && "false".equals(attribute.getValue())) {
                        Object value = null;
                        if (attributeParent != null) {
                            Object parentObj = getFieldValue(object, attributeParent.getValue());
                            value = getFieldValue(parentObj, root.getName());
                        } else {
                            //当转换节点存在时，且未true，需要替换'_'
                            if (conversionAttr == null || "false".equals(conversionAttr.getValue())) {
                                value = getFieldValue(object, root.getName());
                            } else {
                                value = getFieldValue(object, root.getName().replace('-', '_'));
                            }
                        }
                        if (StringUtils.isEmpty(value)) {
                            log.info("[" + root.getName() + "  " + nameAttr.getValue() + "]不能为空");
                            throw new NullPointerException("[" + root.getName() + "  " + nameAttr.getValue() + "]不能为空");
                        }
                        if (maxlenAttr != null) {
                            Integer maxlen = Convert.toInt(maxlenAttr.getValue(), 0);
                            Integer curlen = Convert.toInt(Convert.toStr(value, "").length(), 0);
                            if (curlen > maxlen) {
                                log.info("[" + root.getName() + "  " + nameAttr.getValue() + "]长度不能超过" + maxlen + "字符,当前值" + value + "长度为" + curlen + "字符");
                                throw new NullPointerException("[" + root.getName() + "  " + nameAttr.getValue() + "]长度不能超过" + maxlen + "字符,当前值" + value + "长度为" + curlen + "字符");
                            }
                        }
                        if (minlenAttr != null) {
                            Integer minlen = Convert.toInt(minlenAttr.getValue(), 0);
                            Integer curlen = Convert.toInt(Convert.toStr(value, "").length(), 0);
                            if (curlen < minlen) {
                                log.info("[" + root.getName() + "  " + nameAttr.getValue() + "]长度不能少于" + minlen + "字符,当前值" + value + "长度为" + curlen + "字符");
                                throw new NullPointerException("[" + root.getName() + "  " + nameAttr.getValue() + "]长度不能少于" + minlen + "字符,当前值" + value + "长度为" + curlen + "字符");
                            }
                        }
                        //设置对应的参数值
                        root.setText(String.valueOf(value));
                    } else {
                        //可以为空字段，如果java实体类中字段值不为空，则赋值
//                    Object value = getFieldValue(object, root.getName());
                        Object value = null;
                        //log.info("attributeParent"+attributeParent);
                        if (attributeParent != null) {
                            Object parentObj = getFieldValue(object, attributeParent.getValue());
                            if (conversionAttr == null || "false".equals(conversionAttr.getValue())) {
                                value = getFieldValue(object, root.getName());
                            } else {
                                value = getFieldValue(object, root.getName().replace('-', '_'));
                            }
                        } else {
                            if (conversionAttr == null || "false".equals(conversionAttr.getValue())) {
                                value = getFieldValue(object, root.getName());
                            } else {
                                value = getFieldValue(object, root.getName().replace('-', '_'));
                            }
                        }
                        // log.info("属性:"+root.getName()+"的值为"+value);
                        if (!StringUtils.isEmpty(value)) {
                            if (maxlenAttr != null) {
                                Integer maxlen = Convert.toInt(maxlenAttr.getValue(), 0);
                                Integer curlen = Convert.toInt(Convert.toStr(value, "").length(), 0);
                                if (curlen > maxlen) {
                                    log.info("[" + root.getName() + "  " + nameAttr.getValue() + "]长度不能超过" + maxlen + "字符,当前值" + value + "长度为" + curlen + "字符");
                                    throw new NullPointerException("[" + root.getName() + "  " + nameAttr.getValue() + "]长度不能超过" + maxlen + "字符,当前值" + value + "长度为" + curlen + "字符");
                                }
                            }
                            if (minlenAttr != null) {
                                Integer minlen = Convert.toInt(minlenAttr.getValue(), 0);
                                Integer curlen = Convert.toInt(Convert.toStr(value, "").length(), 0);
                                if (curlen < minlen) {
                                    log.info("[" + root.getName() + "  " + nameAttr.getValue() + "]长度不能少于" + minlen + "字符,当前值" + value + "长度为" + curlen + "字符");
                                    throw new NullPointerException("[" + root.getName() + "  " + nameAttr.getValue() + "]长度不能少于" + minlen + "字符,当前值" + value + "长度为" + curlen + "字符");
                                }
                            }
                            //如果不为null设置值
                            root.setText(String.valueOf(value));
                        }
                    }
                }
                //移除添加的属性
                removeAttribute(root);
            }
            return true;
        }
    }

    private static Boolean setListNodes(Object object, Element root, String nodeType) throws NoSuchFieldException, IllegalAccessException {
        Object obj = null;
        obj = getTValue(object, root.getName(), nodeType);
        List list = (List) obj;
        Element parent = root.getParent();
        parent.remove(root);
        Attribute type = root.attribute("type");
        root.remove(type);
        //数组长度
        int size = 0;
        if (list != null) {
            size = list.size();
        }
        for (int i = 0; i < size; i++) {
            root.addAttribute("index", Convert.toStr(i));
            Element clone = (Element) root.clone();
            setNodes(list.get(i), clone);
            parent.add(clone);
        }
        return true;
    }

    /**
     * 移除属性
     *
     * @param root
     * @author xiaoGang
     */
    public static void removeAttribute(Element root) {
        List<Attribute> attributeList = new ArrayList<>();
        for (Attribute attribute : root.attributes()) {
            //移除属性
            attributeList.add(attribute);
        }
        for (Attribute attribute : attributeList) {
            root.remove(attribute);
        }
    }

    public static Field getField(Object object, String fileName) throws
            NoSuchFieldException, IllegalAccessException {
        //当filename中包含'-',全部替换成'_'
        Field field = null;
        if ("trans_acc_flag".equals(fileName)) {
            if (fileName != null && fileName.contains("-")) {
                fileName = fileName.replace("-", "_");
            }
            Class clazz = object.getClass();
            List<Field> fieldsList = new ArrayList<>();  // 保存属性对象数组到列表
            while (clazz != null) {  // 遍历所有父类字节码对象
                Field[] declaredFields = clazz.getDeclaredFields();  // 获取字节码对象的属性对象数组
                for (Field fieldtmp : declaredFields) {
//                log.info("field type:"+fieldtmp.getType().toString());
//                log.info("field name:"+fieldtmp.getName());
                    String typeStr = fieldtmp.getType().toString();
                    fieldsList.add(fieldtmp);
                }
                clazz = clazz.getSuperclass();  // 获得父类的字节码对象
            }
            field = null;
            for (Field field1 : fieldsList) {
                if (field1.getName().equals(fileName)) {
                    field = field1;
                    break;
                }
            }
        } else {
            if (fileName != null && fileName.contains("-")) {
                fileName = fileName.replace("-", "_");
            }
            Class clazz = object.getClass();
            List<Field> fieldsList = new ArrayList<>();  // 保存属性对象数组到列表
            while (clazz != null) {  // 遍历所有父类字节码对象
                Field[] declaredFields = clazz.getDeclaredFields();  // 获取字节码对象的属性对象数组
                for (Field fieldtmp : declaredFields) {
//                log.info("field type:"+fieldtmp.getType().toString());
//                log.info("field name:"+fieldtmp.getName());
                    String typeStr = fieldtmp.getType().toString();
                    fieldsList.add(fieldtmp);
                }
                clazz = clazz.getSuperclass();  // 获得父类的字节码对象
            }

            for (Field field1 : fieldsList) {
                if (field1.getName().equals(fileName)) {
                    field = field1;
                    break;
                }
            }
        }
        return field;
    }

    public static Field getTField(Object object, String fileName, String nodeType) throws
            NoSuchFieldException, IllegalAccessException {
        Class clazz = object.getClass();
        List<Field> fieldsList = new ArrayList<>();  // 保存属性对象数组到列表
        while (clazz != null) {  // 遍历所有父类字节码对象
            Field[] declaredFields = clazz.getDeclaredFields();  // 获取字节码对象的属性对象数组
            for (Field fieldtmp : declaredFields) {
//                log.info("field type:"+fieldtmp.getType().toString());
//                log.info("field name:"+fieldtmp.getName());
                Class<?> type = fieldtmp.getType();
                if (type == java.util.List.class) {
                    fieldsList.add(fieldtmp);
                }

            }
            clazz = clazz.getSuperclass();  // 获得父类的字节码对象
        }
        Field field = null;
        boolean flag = false;
        for (Field field1 : fieldsList) {
            Type genericType = field1.getGenericType();
            if (genericType == null) {
                continue;
            }
            if (flag) {
                break;
            }
            if (genericType instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) genericType;
                Type[] actualTypeArguments = pt.getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    String typeName = actualTypeArgument.getTypeName();

                    typeName = typeName.substring(typeName.lastIndexOf(".") + 1, typeName.length());
//                    if (typeName.equals(fileName) || "REQINFOST272001".equals(typeName)  || "REQINFOST271020".equals(typeName)) {
//                    if (typeName.equals(fileName)) {
                    field = field1;
                    flag = true;
                    break;
//                    }else if ("listT272001".equals(nodeType)){//针对REQINFOS的list
//                        if ("REQINFOST272001".equals(typeName)){
//                            field = field1;
//                            flag = true;
//                            break;
//                        }
//                    }else if ("listT271020".equals(nodeType)){//针对REQINFOS的list
//                        if ("REQINFOST271020".equals(typeName)){
//                            field = field1;
//                            flag = true;
//                            break;
//                        }
//                    }
                }

            }
        }
        return field;
    }

    /**
     * 获取字段值
     *
     * @param fileName
     * @return
     */
    public static Object getFieldValue(Object object, String fileName) throws
            NoSuchFieldException, IllegalAccessException {
        log.debug("获取对象属性:" + fileName);
        Field field = getField(object, fileName);
        field.setAccessible(true);
        return field.get(object);
    }

    /**
     * 获取泛型
     *
     * @param fileName
     * @return
     */
    public static Object getTValue(Object object, String fileName, String nodeType) throws
            NoSuchFieldException, IllegalAccessException {
        log.debug("获取对象属性:" + fileName);
        Field field = getTField(object, fileName, nodeType);
        field.setAccessible(true);
        return field.get(object);
    }

    /**
     * 设置值
     *
     * @param object
     * @param fileName
     * @param value
     * @throws Exception
     */
    public static void setFieldValue(Object object, String fileName, Object value, Element root) {
        try {
            log.info("获取属性 name=" + fileName);
            log.info("属性对象:{}" + object);
            Field field = getField(object, fileName);
            if (field == null) {
                //如果查不到Field，就去父节点去找
                Object parentObj = getFieldValue(object, root.getParent().getName());
                field = getField(parentObj, fileName);
                object = parentObj;
            }
            log.info("设置属性值 name=" + field.getName() + " value=" + value);
            field.setAccessible(true);
            if (field.getType() == Double.class) {
                field.set(object, Convert.toDouble(value));
            } else if (field.getType() == Integer.class) {
                field.set(object, Convert.toInt(value));
            } else if (field.getType() == Float.class) {
                field.set(object, Convert.toFloat(value));
            } else if (field.getType() == BigDecimal.class) {
                field.set(object, Convert.toBigDecimal(value));
            } else if (field.getType() == Date.class) {
                field.set(object, Convert.toDate(value));
            } else if (field.getType() == Long.class) {
                field.set(object, Convert.toLong(value));
            } else if (field.getType() == String.class) {
                field.set(object, value);
            } else {
                field.set(object, value);
            }
        } catch (NoSuchFieldException e) {
            log.warn("多渠道返回多余字段[" + fileName + "]该系统暂时无用");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static String mergeHostXml(String xmlName) {
        Document sent_host = DOCUMENT_MAP.get("send_HOST.xml");

        Element parent = sent_host.getRootElement();
        Element flows = parent.element("Body").element("request");

        Document read = DOCUMENT_MAP.get("send_HOST_" + xmlName + ".xml");
        List<Element> elements = read.getDocument().getRootElement().elements();
        for (Element emt : elements) {
            flows.add(emt.detach());
        }
        deleteXmlNotation(sent_host.getRootElement());
        return sent_host.asXML();

    }

    public static void main(String[] args) {
        String a = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<Service>\n" +
                "	<Service_Header>\n" +
                "		<reply_qmgr>QMG2GW07</reply_qmgr>\n" +
                "		<service_response>\n" +
                "			<code>00</code>\n" +
                "			<desc>交易成功</desc>\n" +
                "			<status>COMPLETE</status>\n" +
                "		</service_response>\n" +
                "		<msglog>1</msglog>\n" +
                "		<timeout>150</timeout>\n" +
                "		<start_time>1614046973555</start_time>\n" +
                "		<start_timestamp>2021-02-23 10:22:53.554</start_timestamp>\n" +
                "		<name>小额消费</name>\n" +
                "		<service_sn>1740401005009522258</service_sn>\n" +
                "		<service_id>03270000500826</service_id>\n" +
                "		<requester_id>0528</requester_id>\n" +
                "		<branch_id sys_id=\"0001\">321105010</branch_id>\n" +
                "		<channel_id>01</channel_id>\n" +
                "		<version_id>01</version_id>\n" +
                "		<need_request>true</need_request>\n" +
                "		<PutTime>1614046703</PutTime>\n" +
                "		<trace_msg>Reply to responseQ - IBM.SERVICE.RESPONSE.OUT.APOS: QMG2GW07</trace_msg>\n" +
                "		<end_timestamp>2021-02-23 10:22:55.267</end_timestamp>\n" +
                "   </Service_Header>/n" +
                "	<Service_Body>\n" +
                "		<ext_attributes>\n" +
                "			<channelcode>004</channelcode>\n" +
                "			<channeldate>20210223</channeldate>\n" +
                "			<channelseq>000522258</channelseq>\n" +
                "			<brno>321105010</brno>\n" +
                "			<templatecode>500000</templatecode>\n" +
                "			<transcode>500826</transcode>\n" +
                "			<sysid>000022</sysid>\n" +
                "			<terminal_unitno>924301070110025</terminal_unitno>\n" +
                "			<terminal_name>扬中农村商户20180808</terminal_name>\n" +
                "			<terminalno>40401005</terminalno>\n" +
                "			<terminal_acctno>3202230011990010024234</terminal_acctno>\n" +
                "			<INM-ENC-DEV-ID>pos.40401005.zpk</INM-ENC-DEV-ID>\n" +
                "			<INM-PAGE-UP-DOWN>2</INM-PAGE-UP-DOWN>\n" +
                "			<plat_version>two_plat</plat_version>\n" +
                "			<feeflag>0</feeflag>\n" +
                "			<discountrate>0</discountrate>\n" +
                "			<trans_acc_flag>1</trans_acc_flag>\n" +
                "		</ext_attributes>\n" +
                "		<response>\n" +
                "			<agentserialno>0068010486</agentserialno>\n" +
                "			<hostagentserialno>321105010P030000056</hostagentserialno>\n" +
                "			<icdata>9F360201EB910A0AB7695A68177A8E3030</icdata>\n" +
                "			<dzdate>20210223</dzdate>\n" +
                "			<dzserialno>321105010P030000056</dzserialno>\n" +
                "			<obcode>14243000</obcode>\n" +
                "			<recvcode>14243000</recvcode>\n" +
                "			<recvbankname>江苏高淳农村商业银行营业部</recvbankname>\n" +
                "			<xf_amount></xf_amount>\n" +
                "			<yh_amount></yh_amount>\n" +
                "			<sj_amount></sj_amount>\n" +
                "		</response>\n" +
                "		<MAC>None</MAC>\n" +
                "	</Service_Body>\n" +
                "</Service>";
        try {
            // CardResESBInfo cardResESBInfo=toBean(a, CardResESBInfo.class);
            //log.info("cardResESBInfo:{}",JSON.toJSONString(cardResESBInfo));
        } catch (Exception e) {
            log.info("e:{}", e.getMessage());
        }
    }

    public static <T> T fromXml(String xml, Class<T> type) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(type);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        T t = (T) unmarshaller.unmarshal(new StringReader(xml));
        return t;
    }

    public static String beanToXml(Object obj) throws JsonProcessingException {
        XmlMapper xmlMapper = new XmlMapper();
        //设置xml格式携带版本号和编码信息
        xmlMapper.enable(ToXmlGenerator.Feature.WRITE_XML_DECLARATION);
        xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
        return xmlMapper.writeValueAsString(obj);
    }
}
